오늘 풀어본 문제는 백준의 10775번 문제1이다. 문제 풀이에 사용한 언어는 C++ 이다.
이 문제의 내용과 조건은 다음과 같다.
오늘은 신승원의 생일이다.
박승원은 생일을 맞아 신승원에게 인천국제공항을 선물로 줬다.
공항에는 개의 게이트가 있으며 각각은 에서 까지의 번호를 가지고 있다.
공항에는 개의 비행기가 순서대로 도착할 예정이며, 당신은 번째 비행기를 번부터 번째 게이트중 하나에 영구적으로 도킹하려 한다. 비행기가 어느 게이트에도 도킹할 수 없다면 공항이 폐쇄되고, 이후 어떤 비행기도 도착할 수 없다.
신승원은 가장 많은 비행기를 공항에 도킹시켜서 박승원을 행복하게 하고 싶어한다. 승원이는 비행기를 최대 몇 대 도킹시킬 수 있는가?
첫 번째 줄에는 게이트의 수 가 주어진다.
두 번째 줄에는 비행기의 수 가 주어진다.
이후 개의 줄에 가 주어진다.
승원이가 도킹시킬 수 있는 최대의 비행기 수를 출력한다.
문제를 해결하기 위해서 생각한 것은 그리디 알고리즘으로, 게이트의 번호가 작을 수록 수용할 수 있는 종류가 다양하기 때문에 우선적으로 들어오는 비행기들은 가능한한 가장 큰 게이트의 번호를 할당하는 방식을 생각하였다.
문제는 할당해줄 수 있는 가장 큰 게이트를 찾는 것이었는데, 매번 탐색하여 찾는 것은 시간 초과가 발생할 수 있기 때문에 DisjointSet
을 활용하기로 하였다. 앞의 번호와 현재 번호를 Union 하여 Find 를 이용하여 사용 가능한 가장 큰 번호의 게이트를 얻는 방식을 생각한 것이다.
지난번에 분리 집합을 사용하는 문제에서 기존의 DisjointSet
에서 rank
를 없애고 숫자의 대소비교를 이용했는데, 이번 문제를 풀면서 인자를 하나 더 제공하여 원한다면 랭크를 미리 오름차순이나 내림차순으로 줄 수 있도록 설정하였다.
코드는 다음과 같이 작성하였다.
#ifndef __DISJOINT_SET_HPP__
#define __DISJOINT_SET_HPP__
#include <vector>
class DisjointSet {
private:
std::vector<int> parent;
std::vector<int> rank;
public:
DisjointSet(int n, int order = 0) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = i * order;
}
}
int find(int u) {
if (u == parent[u]) {
return u;
}
else {
return parent[u] = find(parent[u]);
}
}
void merge(int u, int v) {
u = find(u);
v = find(v);
if (u != v) {
if (rank[u] > rank[v]) {
std::swap(u, v);
}
parent[u] = v;
if (rank[u] == rank[v]) {
rank[v]++;
}
}
}
};
#endif // !__DISJOINT_SET_HPP__
#include <bits/stdc++.h>
#include "disjoint_set.hpp"
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int G, P;
cin >> G >> P;
vector<int> g(P, 0);
for (int i=0; i<P; i++) {
cin >> g[i];
}
DisjointSet diset(G+1, -1);
int result = 0;
for (int i=0; i<P; i++) {
int gate = diset.find(g[i]);
if (gate != 0) {
result++;
diset.merge(gate - 1, gate);
}
else {
break;
}
}
cout << result;
return 0;
}
그러자 모든 테스트 케이스를 통과하고 ‘맞았습니다’가 나오는 것을 확인할 수 있었다.
확실히 CLASS 5 문제들에서 DisjointSet
을 활용하는 문제들이 많이 보이는 것 같다. 앞으로 11문제 정도 남았으니, 한 두 문제 정도는 DisjointSet
을 활용하는 문제가 나올 것 같은데 과연 어떨지 궁금하다.
여담으로 내가 만든 DisjointSet
자료구조는 내 깃헙 레포지토리2에서 확인할 수 있다. 필요한 사람은 참고하길 바란다.
오늘의 PS는 여기까지!
1: https://www.acmicpc.net/problem/10775
2: https://github.com/ChoiCube84/baekjoon-solutions/blob/main/C++/custom_data_structures/disjoint_set.hpp